#include "hand.h"
#include "player.h"
#include "strategy/prob_strategy.h"
#include "strategy/strategy.h"
#include "strategy/winning_strategy.h"
#include <new>
#include <random>
#include <sstream>

/* implementations of Hand */

Hand *Hand::hands[3] = {new Hand(HANDVALUE_BAG), new Hand(HANDVALUE_SCI), new Hand(HANDVALUE_ROC)};

Hand *Hand::getHand(unsigned int val)
{
    return hands[val];
}

bool Hand::isStringerThan(Hand *h)
{
    return this->fight(h) == 1;
}

bool Hand::isWeakerThan(Hand *h)
{
    return this->fight(h) == -1;
}

int Hand::fight(Hand *h)
{
    if (this == h)
        return 0;
    else if ((this->handvalue + 1) % 3 == h->handvalue)
        return 1;
    else
        return -1;
}

char *Hand::toString()
{
    return handName[this->handvalue];
}

Hand *Player::nextHand()
{
    return strategy->nextHand();
}

void Player::win()
{
    totalcount++;
    wincount++;
}

void Player::lose()
{
    totalcount++;
    losecount++;
}

void Player::even()
{
    totalcount++;
}

std::string Player::toString()
{
    std::stringstream ss;
    ss << "* Name: " << playerName << "\n";
    ss << "* Game Count: " << totalcount << "\n";
    ss << "* Win Count: " << wincount << "\n";
    ss << "* Lose Count: " << losecount << "\n";
    ss << "* Even Count: " << totalcount - wincount - losecount << "\n";

    std::string str;
    ss >> str;
    return str;
}

Hand *WinningStrategy::nextHand()
{
    if (!won) // if prevhand lose
    {
        prevHand = Hand::getHand(randomSign(engine));
    }

    // if won
    return prevHand;
}

void WinningStrategy::study(bool win)
{
    won = win;
}

unsigned int ProbStrategy::getSum(unsigned int hv)
{
    return history[hv][0] + history[hv][1] + history[hv][2];
}

Hand *ProbStrategy::nextHand()
{
    unsigned int sign;
    auto tmpPara = std::uniform_int_distribution<int>::param_type(0, getSum(prevHand) - 1);
    sign = randomSign(engine, tmpPara);
    Hand *hand;

    for (int i = 0; i < 3; i++)
    {
        if (sign < history[prevHand][i])
        {
            hand = Hand::getHand(i);
            prevHand = currHand;
            currHand = i;
        }
        else
            continue;
    }

    return hand;
}

void ProbStrategy::study(bool win)
{

    if (win)
        history[prevHand][currHand]++;
    else
    {
        history[prevHand][(currHand + 1) % 3]++;
        history[prevHand][(currHand + 2) % 3]++;
    }
}
